package pl.us.ij.plugins.segmentation.commands.cvt;

import ij.ImagePlus;
import ij.process.ColorProcessor;
import ij.process.FloatProcessor;
import ij.process.ImageProcessor;
import pl.us.ij.plugins.segmentation.infrastructure.Command;
import pl.us.ij.plugins.segmentation.infrastructure.CommandParams;
import pl.us.ij.plugins.segmentation.infrastructure.ConvertStrategy;
import pl.us.ij.plugins.segmentation.infrastructure.GrayedColorConvertStrategy;
import pl.us.ij.plugins.segmentation.infrastructure.exceptions.BreakCommandException;

/**
 * Created by IntelliJ IDEA.
 * User: Przemek
 * Date: 2010-01-07
 * Time: 01:06:11
 * To change this template use File | Settings | File Templates.
 */
public class CvtSegmentationCommand extends Command<CvtSegmentationCommandParams> {
    @Override
    protected ConvertStrategy prepareConvertStrategy(ImagePlus imp, CommandParams params) {

        ImageProcessor ip = imp.getProcessor();

        if ( ip instanceof ColorProcessor ) {
            return new GrayedColorConvertStrategy(imp, params);
        }

        return super.prepareConvertStrategy(imp, params);
    }

    @Override
    protected void processImage(FloatProcessor fp) throws BreakCommandException {
        int width = fp.getWidth();
        int height = fp.getHeight();

        ImageProcessor ip = fp;

        float[] copyPixels = (float[]) ip.getPixelsCopy();
        float[] pixels = (float[]) ip.getPixels();

        int colorCount = getParams().getColorCount();
        colorCount = colorCount > 0 ? colorCount : 1;

        int[] colorSums = new int[colorCount];
        int[] colorAvs = new int[colorCount];
        int[] colorCounts = new int[colorCount];
        int[] colorPoint = new int[colorCount];
        int[] colorPointPos = new int[colorCount + 1];

        int step = 256 / (colorCount - 1);
        colorPoint[0] = 0;
        colorPoint[colorCount - 1] = 255;
        for (int i = 1; i < colorCount - 1; i++) {
            colorPoint[i] = colorPoint[i - 1] + step;

        }
        boolean loop = true;

        while (loop) {
            loop = false;

            colorPointPos[0] = 0;
            colorPointPos[colorCount] = 255;
            for (int i = 1; i < colorCount; i++) {
                colorPointPos[i] = colorPoint[i - 1] + (colorPoint[i] - colorPoint[i - 1]) / 2;
            }

            for (int i = 0; i < colorCount; i++) {
                colorSums[i] = 0;
                colorCounts[i] = 0;
            }
            for (int y = 0; y < height; y++) {
                int shiftD = y * width;
                int shiftS = y * width;

                for (int x = 0; x < width; x++) {
                    for (int i = 0; i < colorCount; i++) {

                        if ((copyPixels[shiftD + x] >= colorPointPos[i]) && (copyPixels[shiftD + x] <= colorPointPos[i + 1])) {
                            pixels[shiftS + x] = colorPoint[i];

                            colorSums[i] += pixels[shiftD + x];
                            colorCounts[i]++;
                        }

                    }

                }
            }

            for (int i = 0; i < colorCount; i++) {
                if (colorCounts[i] != 0)
                    colorAvs[i] = colorSums[i] / colorCounts[i];

                if (colorAvs[i] != colorPoint[i]) {
                    loop = true;
                    colorPoint[i] = colorAvs[i];
                }
            }
        }

        fp.setPixels(0, (FloatProcessor) ip);
    }
}
